home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * Copyright © 1991, Rob Glanville
- *
- * by Rob Glanville
- *
- * 7 May 91
- *
- * SonicDriver.c - SONIC driver for John Galt cards
- *
- */
-
- /************************************* Defines ***********************************************/
-
- #include "robix.h"
- #include <stdio.h>
- #include <OSUtils.h>
-
- #define ENet1 0x00
- #define ENet2 0x01
- #define SONIC 0x900000
- #define ENetProm 0x700000
- #define ModeSelect 0x600000 // Word read = Smart mode, word write = dumb mode
- #define SlotA 0xfa000000
- #define SlotB 0xfb000000
-
- /* John Galt card memory offsets */
- #define CDA 0x000100 // CAM descriptor area
- #define TDA 0x000110 // Transmit descriptor area
- #define RDA 0x000120 // Receiver descriptor area
- #define RRA 0x000140 // Receiver resource descriptor area
- #define TxBuffer 0x008000 // Transmit buffer
- #define RxBuffer 0x00A000 // Receive buffer area 1
- #define UpperBits 0x0000 // Upper address bits
- #define FreeMem 0x006000 // All memory above this is free for the taking
-
-
- /************************************* Variables *********************************************/
-
- UBYTE origMMUMode;
- UBYTE globalSlot = ENet1; /* Set the default slot to the first card */
-
- struct {
- UBYTE Destination[6];
- UBYTE Source[6];
- UWORD Length;
- UBYTE Buffer[1500];
- ULONG CRCPad;
- } TxPacket;
-
- struct {
- UBYTE Destination[6];
- UBYTE Source[6];
- UWORD Length;
- UBYTE Buffer[1500];
- ULONG CRC;
- } RxPacket;
-
- /************************************* Constants *********************************************/
-
- UWORD ENet1Address[] = {0x1000,0xe028,0x0877}; /* Slot 1 */
- UWORD ENet2Address[] = {0x1000,0xe028,0x0340}; /* Slot 2 */
- extern UBYTE *slotBases[6];
- UBYTE RegPtr[] = {0,0,1,2,3,4,5,6,7,13,14,20,21,22,23,24,43,33,34,35,36,37,38,39,44,45,46,41,42,40};
- struct {
- UBYTE Address[6];
- } Node [3] = {0x10,0x00,0xe0,0x28,0x08,0x77, /* Slot A card */
- 0x10,0x00,0xe0,0x28,0x03,0x40, /* Slot B card */
- 0x10,0x00,0xe0,0x28,0x08,0x77};/* Slot A card */
-
-
- /************************************* Externals *********************************************/
-
- extern UWORD AlterMemory();
- extern UWORD DisplayMemory();
- extern UWORD FillMemory();
- extern void SyntaxError();
- extern void LineIn();
- extern void Upper();
- extern void ScanDelimiters();
- extern void byteout(UBYTE);
- extern UWORD CPointer;
- extern UBYTE CommandLine[0x100];
- extern UBYTE delimiter;
- extern UWORD GetValue();
- extern ULONG number;
-
- /************************************* Routines **********************************************/
-
- UWORD GetWord(UWORD *Address) {
- UWORD value;
- origMMUMode = true32b;
- SwapMMUMode(&origMMUMode);
- value = *Address;
- SwapMMUMode(&origMMUMode);
- return(value);
- }
-
- void PutWord(UWORD *Address,UWORD value) {
- origMMUMode = true32b;
- SwapMMUMode(&origMMUMode);
- *Address = value;
- SwapMMUMode(&origMMUMode);
- }
-
- void DisplayInterruptRegister(UBYTE slot) {
- UWORD *regBase,intStatus;
- regBase = (UWORD *)(slotBases[slot] + SONIC);
- intStatus = GetWord(regBase+5);
- PutWord(regBase+5,0xffff); /* Reset the interrupt status */
- if (intStatus & 0x4000) printf("Bus retry occurred\n");
- if (intStatus & 0x2000) printf("CD Heartbeat lost\n");
- if (intStatus & 0x1000) printf("Load CAM done\n");
- if (intStatus & 0x0800) printf("Programmed interrupt\n");
- if (intStatus & 0x0400) printf("Packet received\n");
- if (intStatus & 0x0200) printf("Transmission done\n");
- if (intStatus & 0x0100) printf("Transmit error\n");
- if (intStatus & 0x0080) printf("Timer complete\n");
- if (intStatus & 0x0040) printf("Receive descriptors exhausted\n");
- if (intStatus & 0x0020) printf("Receive buffers exhausted\n");
- if (intStatus & 0x0010) printf("Receive buffer area exceeded\n");
- if (intStatus & 0x0008) printf("CRC tally counter rollover\n");
- if (intStatus & 0x0004) printf("Frame alignment error tally counter rollover\n");
- if (intStatus & 0x0002) printf("Missed packet counter rollover\n");
- if (intStatus & 0x0001) printf("Receive FIFO overrun\n");
- }
-
- UWORD WaitForTransmit( UBYTE slot) {
- UWORD *TDAPtr,TxStatus,*regBase;
- ULONG timer;
- /* Build transmit descriptor */
- TDAPtr = (UWORD *)(slotBases[slot] + TDA);
- timer = 0x10000;
- do {
- TxStatus = GetWord(TDAPtr); /* Read the transmitter status */
- } while (((TxStatus & 0x07ff) == 0x0000) && (--timer));
- if (timer) return(False);
- regBase = (UWORD *)(slotBases[slot] + SONIC);
- PutWord(regBase+5,0xffff); /* Reset the interrupt status */
- return(True);
- }
-
- /*
- * Transmit will load the SONIC registers with the proper values to start transmission
- */
- void Transmit(ULONG Buffer, UWORD length, UBYTE slot) {
- UWORD *TDAPtr,*regBase;
- /* Build transmit descriptor */
- length += 14; /* Add in the addresses and length fields */
- TDAPtr = (UWORD *)(slotBases[slot] + TDA);
- PutWord(TDAPtr ,0x0000); /* Set status */
- PutWord(TDAPtr + 1,0x5000); /* Set configuration */
- PutWord(TDAPtr + 2,length); /* Set packet length */
- PutWord(TDAPtr + 3,0x0001); /* Set fragment count */
- PutWord(TDAPtr + 4,Buffer); /* Set lower address */
- PutWord(TDAPtr + 5,0x0000); /* Set upper address */
- PutWord(TDAPtr + 6,length); /* Set fragment length */
- PutWord(TDAPtr + 7,0x0001); /* Set status */
- /* Load registers and start the transmission */
- regBase = (UWORD *)(slotBases[slot] + SONIC);
- PutWord(regBase + 6,0x0000); /* Set upper address */
- PutWord(regBase + 7,TDA); /* Set Lower address */
- PutWord(regBase,0x0002); /* Start transmission */
- }
-
- void BuildPacket(UBYTE slot,UBYTE station,UWORD length) {
- UWORD index;
- UBYTE *SPtr,*DPtr;
- /* Build a packet in local memory */
- for (index=0;index<6;index++) {
- TxPacket.Destination[index] = Node[station].Address[index];
- TxPacket.Source[index] = Node[slot].Address[index];
- }
- TxPacket.Length = length;
- for (index=0;index<length;index++) {
- TxPacket.Buffer[index] = index;
- }
- /* Copy packet to ENet card memory at 0xFX008000 */
- SPtr = (UBYTE *)&TxPacket;
- DPtr = (UBYTE *)(slotBases[slot] + TxBuffer);
- length += 14; /* Add in the addresses and length fields */
- origMMUMode = true32b;
- SwapMMUMode(&origMMUMode);
- for (index=0;index<length;index++) {
- *DPtr++ = *SPtr++;
- }
- SwapMMUMode(&origMMUMode);
- }
-
- void GetPacket(UBYTE slot,UWORD length) {
- UWORD index;
- UBYTE *SPtr,*DPtr;
- /* Copy packet from ENet card memory at 0xFX004000 */
- DPtr = (UBYTE *)&RxPacket;
- SPtr = (UBYTE *)(slotBases[slot] + RxBuffer);
- length += 18; /* Add in the addresses, length and CRC fields */
- origMMUMode = true32b;
- SwapMMUMode(&origMMUMode);
- for (index=0;index<length;index++) {
- *DPtr++ = *SPtr++;
- }
- SwapMMUMode(&origMMUMode);
- }
-
- UWORD ComparePackets(UWORD length) {
- UBYTE failed;
- UWORD index;
- UBYTE *SPtr,*DPtr;
- failed = False;
- SPtr = (UBYTE *)&TxPacket.Buffer;
- DPtr = (UBYTE *)&RxPacket.Buffer;
- for (index=0;index<length;index++) {
- if (*DPtr++ != *SPtr++) {
- failed = True;
- break;
- }
- }
- if (failed) {
- printf("The Buffers miscompared\n");
- return(True);
- }
- else return(False);
- }
-
- /*
- * Transmit packet will build a packet in memory and transmit it
- */
- void TestTransmit(UBYTE slot, UBYTE station, UWORD length) {
- UWORD TxError;
- BuildPacket(slot,station,length);
- Transmit(TxBuffer,length,slot);
- TxError = WaitForTransmit(slot);
- if (TxError) {
- printf("Transmission error, checking status..\n");
- DisplayInterruptRegister(slot);
- }
- }
-
- UWORD WaitForReceive( UBYTE slot ) {
- UWORD *RDAPtr,RxStatus,*regBase;
- ULONG timer;
- RDAPtr = (UWORD *)(slotBases[slot] + RDA); /* Point to RDA */
- timer = 0x10000;
- do {
- RxStatus = GetWord(RDAPtr); /* Read the receiver status */
- } while (((RxStatus & 0x01ff) == 0x0000) && (--timer));
- if (timer) return(False);
- regBase = (UWORD *)(slotBases[slot] + SONIC);
- PutWord(regBase+5,0xffff); /* Reset the interrupt status */
- return(True);
- }
-
- void Receive(ULONG buffer, UWORD length, UBYTE slot) {
- UWORD *RDAPtr,*RRAPtr,*regBase;
-
- /* Build the resource descriptor area */
- length += 18; /* Add in the addresses, length and CRC fields */
- RRAPtr = (UWORD *)(slotBases[slot] + RRA); /* Point to RRA */
- PutWord(RRAPtr ,buffer); /* Set lower address */
- PutWord(RRAPtr + 1,0x0000); /* Set upper address */
- PutWord(RRAPtr + 2,length); /* Set lower length */
- PutWord(RRAPtr + 3,0x0000); /* Set upper length */
-
- /* Build receiver descriptor */
- RDAPtr = (UWORD *)(slotBases[slot] + RDA); /* Point to RDA */
- PutWord(RDAPtr ,0x0000); /* Set status */
- PutWord(RDAPtr + 1,0x0000); /* Set packet length */
- PutWord(RDAPtr + 2,0x0000); /* Set lower address */
- PutWord(RDAPtr + 3,0x0000); /* Set upper address */
- PutWord(RDAPtr + 4,0x0000); /* Set Sequence number */
- PutWord(RDAPtr + 5,0x0001); /* Set link */
- PutWord(RDAPtr + 6,0xffff); /* Set in use */
-
- /* Load registers and get read for reception */
- regBase = (UWORD *)(slotBases[slot] + SONIC); /* Point to SONIC */
- PutWord(regBase + 13,0x0000); /* Set upper address */
- PutWord(regBase + 14,RDA); /* Set Lower address */
- PutWord(regBase + 20,0x0000); /* Set upper address */
- PutWord(regBase + 21,RRA); /* Set Resource start address */
- PutWord(regBase + 22,RRA+4); /* Set Resource end address */
- PutWord(regBase + 23,RRA); /* Set Resource read register */
- PutWord(regBase + 24,RRA+4); /* Set Resource write register */
- PutWord(regBase + 43,0x0000); /* Set Receive sequence counter */
- PutWord(regBase,0x0100); /* Read RRA */
- PutWord(regBase,0x0008); /* Start receiving */
- }
-
- void SONICStatus() {
- UBYTE slot;
- UWORD *regBase;
- ULONG slotBase;
- if (GetValue()) slot = number;
- else slot = ENet1;
- if (slot < ENet1) slot = ENet1;
- if (slot > ENet2) slot = ENet2;
- slotBase = (slotBases[slot] + SONIC);
- regBase = (UWORD *)slotBase;
- printf(" 1) Command %lX = %04X\n",(regBase ),GetWord(regBase ));
- printf(" 2) Configuration %lX = %04X\n",(regBase+1 ),GetWord(regBase+1 ));
- printf(" 3) Rx Control %lX = %04X\n",(regBase+2 ),GetWord(regBase+2 ));
- printf(" 4) Tx Control %lX = %04X\n",(regBase+3 ),GetWord(regBase+3 ));
- printf(" 5) Interrupt Mask %lX = %04X\n",(regBase+4 ),GetWord(regBase+4 ));
- printf(" 6) Interrupt status %lX = %04X\n",(regBase+5 ),GetWord(regBase+5 ));
- printf(" 7) Upper transmit descriptor address %lX = %04X\n",(regBase+6 ),GetWord(regBase+6 ));
- printf(" 8) Current transmit descriptor address %lX = %04X\n",(regBase+7 ),GetWord(regBase+7 ));
- printf(" 9) Upper receiver descriptor address %lX = %04X\n",(regBase+13),GetWord(regBase+13));
- printf("10) Current receiver descriptor address %lX = %04X\n",(regBase+14),GetWord(regBase+14));
- printf("11) Upper receiver resource address %lX = %04X\n",(regBase+20),GetWord(regBase+20));
- printf("12) Resource start address %lX = %04X\n",(regBase+21),GetWord(regBase+21));
- printf("13) Resource end address %lX = %04X\n",(regBase+22),GetWord(regBase+22));
- printf("14) Resource read %lX = %04X\n",(regBase+23),GetWord(regBase+23));
- printf("15) Resource write %lX = %04X\n",(regBase+24),GetWord(regBase+24));
- printf("16) Receive sequence counter %lX = %04X\n",(regBase+43),GetWord(regBase+43));
- printf("17) CAM entry pointer %lX = %04X\n",(regBase+33),GetWord(regBase+33));
- printf("18) CAM address port 2 %lX = %04X\n",(regBase+34),GetWord(regBase+34));
- printf("19) CAM address port 1 %lX = %04X\n",(regBase+35),GetWord(regBase+35));
- printf("20) CAM address port 0 %lX = %04X\n",(regBase+36),GetWord(regBase+36));
- printf("21) CAM Enable %lX = %04X\n",(regBase+37),GetWord(regBase+37));
- printf("22) CAM descriptor pointer %lX = %04X\n",(regBase+38),GetWord(regBase+38));
- printf("23) CAM descriptor count %lX = %04X\n",(regBase+39),GetWord(regBase+39));
- printf("24) CRC error tally counter %lX = %04X\n",(regBase+44),GetWord(regBase+44));
- printf("25) Frame alignment error tally %lX = %04X\n",(regBase+45),GetWord(regBase+45));
- printf("26) Missed packet tally %lX = %04X\n",(regBase+46),GetWord(regBase+46));
- printf("27) Watchdog timer 0 %lX = %04X\n",(regBase+41),GetWord(regBase+41));
- printf("28) Watchdog timer 1 %lX = %04X\n",(regBase+42),GetWord(regBase+42));
- printf("29) Silicon revision register %lX = %04X\n",(regBase+40),GetWord(regBase+40));
- }
-
- /*
- * Display Sonic Registers will display or change one register at a time using logical references
- * as outlined in the SONICStatus routine.
- * The syntax is;
- * g [ register ] [ value ] <cr> , Set register to value
- * g [ register ] <cr> , Display register
- * g <cr> , Display last register
- * This routine plays a trick on the hex register pointer to make it appear to be decimal
- * so hex number between 'a' and 'f' and also '1a' and '1f' are valid but should not be used
- */
- UBYTE RegisterPointer = 0;
- void DisplaySonicRegister() {
- UBYTE setRegister;
- UWORD *regBase,value;
- if (GetValue()) RegisterPointer = number;
- if (RegisterPointer > 0x1f) RegisterPointer -= 12; // Adjust for decimal like index, make 0x20 into 20
- else if (RegisterPointer > 0x0f) RegisterPointer -= 6; // Adjust for decimal like index, make 0x10 into 10
- if (GetValue()) {
- value = number;
- setRegister = True;
- }
- else setRegister = False;
- regBase = (UWORD *)(slotBases[globalSlot] + SONIC + (2 * RegPtr[RegisterPointer]));
- if (setRegister) {
- PutWord(regBase,value);
- }
- else {
- value = GetWord(regBase);
- printf("%lX = %04X\n",regBase,value);
- }
- }
-
- /*
- * Load CAM will place the Ethernet address into the SONIC registers
- */
- void LoadCAM(UBYTE slot) {
- UWORD *CDABase,*regBase,*ENetPromBase,intStatus,AddrWord,AddrWordH,AddrWordL;
- ULONG timer;
- regBase = (UWORD *)(slotBases[slot] + SONIC);
- PutWord(regBase,0x0085); /* Reset and stop operations */
- PutWord(regBase+1,0x0B03); /* Set the configuration register */
- PutWord(regBase,0x0000); /* Remove the reset, stop operations */
- CDABase = (UWORD *)(slotBases[slot] + CDA);
- ENetPromBase = (UWORD *)(slotBases[slot] + ENetProm);
- PutWord(CDABase,0x0000); /* Set the CAM entry pointer */
- AddrWordH = GetWord(ENetPromBase + 1);
- AddrWordL = GetWord(ENetPromBase + 0);
- AddrWord = ((AddrWordH << 8) & 0xff00) + (AddrWordL & 0x00ff);
- PutWord(CDABase+1,AddrWord);
- AddrWordH = GetWord(ENetPromBase + 3);
- AddrWordL = GetWord(ENetPromBase + 2);
- AddrWord = ((AddrWordH << 8) & 0xff00) + (AddrWordL & 0x00ff);
- PutWord(CDABase+2,AddrWord);
- AddrWordH = GetWord(ENetPromBase + 5);
- AddrWordL = GetWord(ENetPromBase + 4);
- AddrWord = ((AddrWordH << 8) & 0xff00) + (AddrWordL & 0x00ff);
- PutWord(CDABase+3,AddrWord);
- PutWord(CDABase+4,0x0001); /* Set the CAM descriptor count */
- PutWord(regBase+20,0x0000); /* Set upper pointer */
- PutWord(regBase+38,CDA); /* Set lower pointer */
- PutWord(regBase+39,0x0001); /* Set descriptor count */
- PutWord(regBase,0x0200); /* Set load CAM command */
- timer = 0x80000;
- do {
- intStatus = GetWord(regBase+5); /* Read the interrupt status */
- } while (((intStatus & 0x1000) != 0x1000) && (--timer));
- }
-
- /*
- * This will send a packet of data from one John Galt Ethernet card to another John Galt card
- * and compare the results.
- * 1) Build a packet in memory and copy it one of the John Galt cards (first card)
- * 2) Tell the second card to get ready for reception
- * 3) Tell the first card to transmit
- * 4) Wait for first card transmit done and report errors
- * 5) Wait for second card receive done and report errors
- * 6) Copy packet from second card to main memory
- * 7) Compare the two packets and report errors
- * 8) Switch source with destination and repeat until loop count is zero
- */
- void CardToCardTest() {
- UBYTE sourceSlot;
- UBYTE destinationSlot;
- UBYTE temporarySlot;
- UWORD length;
- ULONG loopCount;
- if (GetValue()) loopCount = number;
- else loopCount = 1; /* Minimum count */
- if (loopCount == 0) loopCount = 1;
- if (GetValue()) sourceSlot = number;
- else sourceSlot = ENet1;
- if (GetValue()) destinationSlot = number;
- else destinationSlot = ENet2;
- if (GetValue()) length = number;
- else length = 1500; /* Maximum packet size */
- if (length < 64) length = 50; /* Minimum length for data field */
- else if (length > 1500) length = 1500; /* Maximum data length */
- if (sourceSlot < 1) sourceSlot = 1;
- else if (sourceSlot > 2) sourceSlot = 2;
- if (destinationSlot < 1) destinationSlot = 1;
- else if (destinationSlot > 2) destinationSlot = 2;
- if (sourceSlot == destinationSlot) {
- sourceSlot = 1;
- destinationSlot = 2;
- }
-
- /* Build the transmit buffer and send it off to the transmit card */
- BuildPacket(sourceSlot,destinationSlot,length); /* 1) Build a source packet for both cards */
- BuildPacket(destinationSlot,sourceSlot,length); /* 1) Build a source packet for both cards */
- while (loopCount--) {
- Receive(RxBuffer,length,destinationSlot); /* 2) Start Receiver */
- Transmit(TxBuffer,length,sourceSlot); /* 3) Start Transmiter */
- if (WaitForTransmit(sourceSlot)) { /* 4) Wait for transmit */
- DisplayInterruptRegister(sourceSlot); /* 4) Report transmit errors */
- break;
- }
- if (WaitForReceive(destinationSlot)) { /* 5) Wait for receive */
- DisplayInterruptRegister(destinationSlot);/* 5) Report receive errors */
- break;
- }
- GetPacket(destinationSlot,length); /* 6) Copy packet from Enet card to Mac memeory */
- if (ComparePackets(length)) break; /* 7) Compare data and report errors */
- temporarySlot = sourceSlot; /* 8) Switch source and destination */
- sourceSlot = destinationSlot;
- destinationSlot = temporarySlot;
- }
- }
-
- /*********************************** Command Loop ********************************************/
-
- void SONICHelp() {
- printf("?) Print this menu\n");
- printf("A) Alter memory\n");
- printf("B) Display interrupt status\n");
- printf("C) Send packets from card to card\n");
- printf("D) Display memory\n");
- printf("F) Fill memory\n");
- printf("G) Display or modify SONIC register\n");
- printf("L) Load CAM\n");
- printf("Q) Quit\n");
- printf("R) Receive\n");
- printf("S) SONIC status\n");
- printf("T) Transmit 1 to 2\n");
- printf("U) Transmit 2 to 1\n");
- printf("V) Transmit both at once\n");
- printf("X) Exit this menu\n");
- }
-
- /*
- * if ExitMode = 'Q' then quit program, if 'X' then return to main menu
- */
- UBYTE SONICMenu() {
- UBYTE Exit,ExitMode,slot;
- ULONG index,count;
- delimiter = CR;
- Exit = False;
- printf("SONIC control menu\n");
- while (!Exit) {
- if (delimiter == CR) putchar('*');
- LineIn();
- ScanDelimiters(); /* Point to first non Blank */
- Upper(&CommandLine[CPointer]);
- switch(CommandLine[CPointer++]) {
- case '?' :
- SONICHelp();
- break;
- case CR :
- break;
- case 'A' :
- if (AlterMemory()) SyntaxError();
- break;
- case 'B' :
- if (GetValue()) slot = number;
- else slot = ENet1;
- if (slot < ENet1) slot = ENet1;
- if (slot > ENet2) slot = ENet2;
- DisplayInterruptRegister(slot);
- break;
- case 'C' :
- CardToCardTest();
- break;
- case 'D' :
- if (DisplayMemory()) SyntaxError();
- break;
- case 'F' :
- if (FillMemory()) SyntaxError();
- break;
- case 'G' :
- if (GetValue()) slot = number;
- else slot = ENet1;
- if (slot < ENet1) slot = ENet1;
- if (slot > ENet2) slot = ENet2;
- DisplaySonicRegister(slot);
- break;
- case 'L' :
- if (GetValue()) slot = number;
- else slot = ENet1;
- if (slot < ENet1) slot = ENet1;
- if (slot > ENet2) slot = ENet2;
- LoadCAM(slot);
- break;
- case 'Q' :
- Exit = True;
- ExitMode = 'Q';
- printf("Bye...\n");
- break;
- case 'R' :
- if (GetValue()) slot = number;
- else slot = ENet1;
- if (slot < ENet1) slot = ENet1;
- if (slot > ENet2) slot = ENet2;
- Receive(RxBuffer,0x600,slot);
- break;
- case 'S' :
- SONICStatus();
- break;
- case 'T' :
- if (GetValue()) count = number;
- else count = 1;
- if (count == 0) count = 1;
- for (index=0;index<count;index++) {
- TestTransmit(ENet1,ENet2,736);
- }
- break;
- case 'U' :
- if (GetValue()) count = number;
- else count = 1;
- if (count == 0) count = 1;
- for (index=0;index<count;index++) {
- TestTransmit(ENet2,ENet1,926);
- }
- break;
- case 'V' :
- if (GetValue()) count = number;
- else count = 1;
- if (count == 0) count = 1;
- for (index=0;index<count;index++) {
- TestTransmit(ENet1,ENet2,676);
- TestTransmit(ENet2,ENet1,856);
- }
- break;
- case 'X' :
- Exit = True;
- ExitMode = 'X';
- printf("See ya...\n");
- break;
- default :
- printf("Unknown SONIC menu command, %2X\n",CommandLine[--CPointer]);
- CPointer++;
- delimiter = CR;
- break;
- }
- }
- return(ExitMode);
- }
-
-